using System;
using System.Text;

namespace CubeTimer.Scramble
{
  public class Scramble3x3 : Scramble
  {

    private static readonly String[] UandD = { "U", "U'", "U2", "D", "D'", "D2" };
    private static readonly String[] FandB = { "F", "F'", "F2", "B", "B'", "B2" };
    private static readonly String[] LandR = { "L", "L'", "L2", "R", "R'", "R2" };

    readonly int m_numMoves = 25;

    private int m_oldArray, m_previousArray, m_previousFace, m_currentArray, m_currentFace;
    private String m_formatedMove;


    public Scramble3x3(int num)
    {
      m_numMoves = num;
    }

    public override string Name
    {
      get { return "3x3x3"; }
    }

    private void GenerateMove()
    {
      m_currentArray = Math.Abs(m_generator.Next()) % 3;
      m_currentFace = Math.Abs(m_generator.Next()) % 6;

      String[] arrayChoice = null;
      switch (m_currentArray)
      {
        case 0:
          arrayChoice = UandD;
          break;
        case 1:
          arrayChoice = FandB;
          break;
        case 2:
          arrayChoice = LandR;
          break;
      }

      if (arrayChoice != null) 
        m_formatedMove = arrayChoice[m_currentFace];
    }

    public override String GenerateScramble()
    {
      StringBuilder buf = new StringBuilder(3 * m_numMoves);
      // generate new move
      GenerateMove();

      // add first move to scramble
      buf.Append(m_formatedMove);

      // store current move so that we can generate a new one
      m_previousArray = m_currentArray;
      m_previousFace = m_currentFace;

      // generate new move
      GenerateMove();

      // while this move is the same face, generate a new one
      while (IsSameFace(m_currentArray, m_currentFace, m_previousArray, m_previousFace))
      {
        GenerateMove();
      }

      // add second move to scramble
      buf.Append(" ");
      buf.Append(m_formatedMove);

      // store previous and current move so that we can generate a new one
      m_oldArray = m_previousArray;
      m_previousArray = m_currentArray;
      m_previousFace = m_currentFace;

      // we have two moves of the scramble. Now we need to generate the rest.
      for (int i = 0; i < m_numMoves - 2; i++)
      {
        // generate a new move
        GenerateMove();

        // If the first two moves are parallel
        if (IsParallel(m_previousArray, m_oldArray))
        {
          // loop until third move is not parallel
          while (IsParallel(m_currentArray, m_previousArray))
          {
            GenerateMove();
          }
        }
        else
        {
          // loop until the next move is not the same face as the previous
          while (IsSameFace(m_currentArray, m_currentFace, m_previousArray, m_previousFace))
          {
            GenerateMove();
          }
        }

        // add this move to scramble
        buf.Append(" ");
        buf.Append(m_formatedMove);

        // store previous and current move so that we can generate a new one
        m_oldArray = m_previousArray;
        m_previousArray = m_currentArray;
        m_previousFace = m_currentFace;
      }
      return buf.ToString();
    } // end Generate Scramble

    private static bool IsSameFace(int thisArray, int thisFace, int thatArray,
                                   int thatFace)
    {
      if ((thisArray == thatArray))
      {
        return ((thisFace == 0 || thisFace == 1 || thisFace == 2) &&
                (thatFace == 0 || thatFace == 1 || thatFace == 2)) ||
               ((thisFace == 3 || thisFace == 4 || thisFace == 5) &&
                (thatFace == 3 || thatFace == 4 || thatFace == 5));
      }
      return false;
    }

    private static bool IsParallel(int thisArray, int thatArray)
    {
      return thisArray == thatArray;
    }
  }
}